import os
import json
import logging
from typing import Dict, Any, Optional

class ConfigLoader:
    """
    配置加载器，负责加载和管理配置文件
    支持默认配置和用户自定义配置的合并
    """
    
    # 默认配置
    DEFAULT_CONFIG = {
        "parallel_engine": {
            "max_workers": 8,
            "task_queue_size": 100,
            "load_balancing": True,
            "device_allocation_strategy": "optimal"
        },
        "smart_wait": {
            "default_timeout": 30,
            "polling_interval": 0.1,
            "adaptive_timeout": True,
            "max_retries": 3,
            "backoff_factor": 1.5
        },
        "resource_manager": {
            "pool_enabled": True,
            "max_pool_size": 20,
            "connection_timeout": 60,
            "reuse_threshold": 3,
            "cleanup_interval": 300
        },
        "performance_monitor": {
            "enabled": True,
            "metrics_collection_interval": 1.0,
            "report_format": "json",
            "export_path": "./reports"
        },
        "logging": {
            "level": "INFO",
            "format": "%(asctime)s - %(name)s - %(levelname)s - %(message)s",
            "file_path": "./logs/harmony_test.log"
        }
    }
    
    def __init__(self, config_path: Optional[str] = None):
        """
        初始化配置加载器
        
        Args:
            config_path: 配置文件路径，None使用默认配置
        """
        self.config_path = config_path
        self.config = self.DEFAULT_CONFIG.copy()
        
        # 初始化日志
        logging.basicConfig(
            level=getattr(logging, self.config['logging']['level']),
            format=self.config['logging']['format']
        )
        self.logger = logging.getLogger('ConfigLoader')
        
        # 加载配置文件
        if config_path:
            self.load_config(config_path)
        else:
            self.logger.info("未指定配置文件路径，使用默认配置")
    
    def load_config(self, config_path: str):
        """
        从文件加载配置
        
        Args:
            config_path: 配置文件路径
            
        Raises:
            FileNotFoundError: 配置文件不存在
            json.JSONDecodeError: 配置文件格式错误
        """
        # 检查文件是否存在
        if not os.path.exists(config_path):
            self.logger.warning(f"配置文件不存在: {config_path}，将使用默认配置")
            # 尝试查找默认配置位置
            default_locations = [
                os.path.join(os.getcwd(), "config.json"),
                os.path.join(os.getcwd(), "config", "config.json"),
                os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "config", "config.json")
            ]
            
            found = False
            for loc in default_locations:
                if os.path.exists(loc):
                    self.logger.info(f"在默认位置找到配置文件: {loc}")
                    config_path = loc
                    found = True
                    break
            
            if not found:
                self.logger.warning("未找到任何配置文件，继续使用默认配置")
                return
        
        # 加载配置文件
        try:
            with open(config_path, 'r', encoding='utf-8') as f:
                user_config = json.load(f)
            
            # 合并配置
            self.merge_config(user_config)
            self.logger.info(f"成功加载配置文件: {config_path}")
        except json.JSONDecodeError as e:
            self.logger.error(f"配置文件格式错误: {str(e)}")
            raise
        except Exception as e:
            self.logger.error(f"加载配置文件失败: {str(e)}")
            raise
    
    def merge_config(self, user_config: Dict[str, Any]):
        """
        合并用户配置到默认配置
        
        Args:
            user_config: 用户配置
        """
        def deep_merge(default: Dict[str, Any], user: Dict[str, Any]) -> Dict[str, Any]:
            """深度合并两个字典"""
            result = default.copy()
            
            for key, value in user.items():
                if key in result and isinstance(result[key], dict) and isinstance(value, dict):
                    # 递归合并子字典
                    result[key] = deep_merge(result[key], value)
                else:
                    # 直接覆盖
                    result[key] = value
            
            return result
        
        self.config = deep_merge(self.config, user_config)
        self.logger.debug("配置合并完成")
    
    def get_config(self) -> Dict[str, Any]:
        """
        获取当前配置
        
        Returns:
            配置字典
        """
        return self.config.copy()
    
    def get(self, key_path: str, default: Any = None) -> Any:
        """
        获取指定路径的配置值
        
        Args:
            key_path: 配置键路径，支持点号分隔，如 "parallel_engine.max_workers"
            default: 默认值
            
        Returns:
            配置值或默认值
        """
        keys = key_path.split('.')
        value = self.config
        
        try:
            for key in keys:
                value = value[key]
            return value
        except (KeyError, TypeError):
            self.logger.warning(f"配置项不存在: {key_path}，返回默认值: {default}")
            return default
    
    def set(self, key_path: str, value: Any):
        """
        设置指定路径的配置值
        
        Args:
            key_path: 配置键路径，支持点号分隔
            value: 配置值
        """
        keys = key_path.split('.')
        config = self.config
        
        # 遍历到倒数第二个键
        for key in keys[:-1]:
            if key not in config or not isinstance(config[key], dict):
                config[key] = {}
            config = config[key]
        
        # 设置最终值
        config[keys[-1]] = value
        self.logger.debug(f"设置配置项: {key_path} = {value}")
    
    def validate_config(self) -> bool:
        """
        验证配置的有效性
        
        Returns:
            是否有效
        """
        try:
            # 验证必要的配置项
            required_sections = ['parallel_engine', 'smart_wait', 'resource_manager']
            for section in required_sections:
                if section not in self.config:
                    self.logger.error(f"缺少必要的配置节: {section}")
                    return False
            
            # 验证并行引擎配置
            if not isinstance(self.config['parallel_engine'].get('max_workers'), int) or \
               self.config['parallel_engine']['max_workers'] < 1:
                self.logger.error("并行引擎配置无效: max_workers 必须是大于0的整数")
                return False
            
            # 验证智能等待配置
            if not isinstance(self.config['smart_wait'].get('default_timeout'), (int, float)) or \
               self.config['smart_wait']['default_timeout'] <= 0:
                self.logger.error("智能等待配置无效: default_timeout 必须是大于0的数字")
                return False
            
            # 验证资源管理器配置
            if not isinstance(self.config['resource_manager'].get('max_pool_size'), int) or \
               self.config['resource_manager']['max_pool_size'] < 1:
                self.logger.error("资源管理器配置无效: max_pool_size 必须是大于0的整数")
                return False
            
            self.logger.info("配置验证通过")
            return True
        except Exception as e:
            self.logger.error(f"配置验证失败: {str(e)}")
            return False
    
    def export_config(self, output_path: str):
        """
        导出当前配置到文件
        
        Args:
            output_path: 输出文件路径
        """
        try:
            # 确保目录存在
            os.makedirs(os.path.dirname(output_path), exist_ok=True)
            
            # 保存配置
            with open(output_path, 'w', encoding='utf-8') as f:
                json.dump(self.config, f, indent=2, ensure_ascii=False)
            
            self.logger.info(f"配置已导出到: {output_path}")
        except Exception as e:
            self.logger.error(f"导出配置失败: {str(e)}")
            raise

# 全局配置加载器实例
_config_loader_instance = None


def get_config_loader(config_path: Optional[str] = None) -> ConfigLoader:
    """
    获取全局配置加载器实例
    
    Args:
        config_path: 配置文件路径
        
    Returns:
        ConfigLoader实例
    """
    global _config_loader_instance
    if _config_loader_instance is None:
        _config_loader_instance = ConfigLoader(config_path)
    return _config_loader_instance


def get_config() -> Dict[str, Any]:
    """
    获取全局配置
    
    Returns:
        配置字典
    """
    return get_config_loader().get_config()


def get_config_value(key_path: str, default: Any = None) -> Any:
    """
    获取指定路径的配置值
    
    Args:
        key_path: 配置键路径
        default: 默认值
        
    Returns:
        配置值或默认值
    """
    return get_config_loader().get(key_path, default)